package com.pioneer.cloudstorage.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.pioneer.cloudstorage.common.constant.RedisConstants;
import com.pioneer.cloudstorage.mapper.SharesMapper;
import com.pioneer.cloudstorage.pojo.dto.SharesDTO;
import com.pioneer.cloudstorage.pojo.entity.*;
import com.pioneer.cloudstorage.pojo.vo.GetshareVo;
import com.pioneer.cloudstorage.pojo.vo.SharesList;
import com.pioneer.cloudstorage.service.FilesService;
import com.pioneer.cloudstorage.service.SharesService;
import com.pioneer.cloudstorage.utils.AESUtils;
import com.pioneer.cloudstorage.utils.BCryptUtils;
import com.pioneer.cloudstorage.utils.BaseContext;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.crypto.SecretKey;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static com.pioneer.cloudstorage.utils.BCryptUtils.encryptPassword;

@Service
@Slf4j
public class SharesServiceImpl extends ServiceImpl<SharesMapper, Share> implements SharesService {
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private SharesMapper sharesMapper;

    // 在类级别定义格式化器
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    @Autowired
    private AESUtils aesUtils;
    @Transactional
    @Override
    public String share(SharesDTO sharesDTO) throws Exception {
        //生成唯一 `shareId`（UUID），去掉连字符为32字符
        String shareId = UUID.randomUUID().toString().replace("-", "");
        Long userId = BaseContext.getCurrentId();
        //加密密码
        String password = aesUtils.encrypt( sharesDTO.getPassword());
        Share share = Share.builder()
                .id(shareId)
                .fileId(sharesDTO.getFileId())
                .userId(userId)
                .password(password)
                .expireTime(sharesDTO.getExpireTime())
                .createdTime(null)
                .build();
        this.save(share);
        Share_Redis shareInfo = Share_Redis.builder()
                .fileId(share.getFileId())
                .userId(share.getUserId())
                .password(password)
                .expireTime(String.valueOf(share.getExpireTime()))
                .build();
       String shareId1 = RedisConstants.share_prefix + shareId;
        //将包含时区格式的时间转为yyyy-MM-dd HH:mm:ss
        // 使用格式化器
        String formattedTime = share.getExpireTime().format(FORMATTER);
        shareInfo.setExpireTime(formattedTime);
        stringRedisTemplate.opsForValue().set(shareId1, JSONUtil.toJsonStr(shareInfo), RedisConstants.share_ttl, TimeUnit.MINUTES);
        return shareId;
    }

@Override
public List<SharesList> getShareList() throws Exception {
    Long userId = BaseContext.getCurrentId();
    List<Share> shareList = this.list(new LambdaQueryWrapper<Share>().eq(Share::getUserId, userId));
    List<SharesList> shareListVo = new ArrayList<>();

    for (Share share : shareList) {
        // 创建新的 SharesList 实例
        SharesList sharesList =new SharesList();

        String fileName = sharesMapper.getFileNameById(share.getFileId());
        sharesList.setFileName(fileName);
        sharesList.setFileId(share.getFileId());
        sharesList.setExpireTime(share.getExpireTime());
        log.info("ExpireTime: " + sharesList.getExpireTime());
        sharesList.setId(share.getId());
        sharesList.setCreatedAt(share.getCreatedTime());
        String password = aesUtils.decrypt(share.getPassword());
        sharesList.setPassword(password);
        shareListVo.add(sharesList);
    }

    return shareListVo;
}

@Override
    public Result deleteShare(String shareId) {
        String shareInfo = stringRedisTemplate.opsForValue().get(RedisConstants.share_prefix + shareId);
        if (shareInfo == null) {
            return Result.error("分享链接不存在");
        }
        Share_Redis share = JSONUtil.toBean(shareInfo, Share_Redis.class);
        Long userId = BaseContext.getCurrentId();
        if (!share.getUserId().equals(userId)) {
            return Result.error("您没有权限删除此分享链接");
        }
        stringRedisTemplate.delete(RedisConstants.share_prefix + shareId);
        this.removeById(shareId);
        return Result.success();
    }
   @Override
public Result getShare(String shareId, String password) throws Exception {
    //1. 先查 Redis，未命中再查 MySQL。
    String shareInfo = stringRedisTemplate.opsForValue().get(RedisConstants.share_prefix + shareId);
    Share_Redis share = null;

    if (shareInfo == null) {
        Share dbShare = this.getById(shareId);
        if (dbShare == null) {
            return Result.error("分享链接不存在");
        }

        // 将数据库中的Share对象转换为Share_Redis对象并存入Redis
          share = new Share_Redis();
        share.setFileId(dbShare.getFileId());
        share.setUserId(dbShare.getUserId());
        share.setPassword(dbShare.getPassword());
        // 使用格式化器格式化时间
        String formattedTime = dbShare.getExpireTime().format(FORMATTER);
        share.setExpireTime(formattedTime);

        // 存入Redis
        stringRedisTemplate.opsForValue().set(
            RedisConstants.share_prefix + shareId,
            JSONUtil.toJsonStr(share),
            RedisConstants.share_ttl,
            TimeUnit.MINUTES
        );
    } else {
        share = JSONUtil.toBean(shareInfo, Share_Redis.class);
    }
    //2. 校验密码及过期时间。
    if (share.getPassword() != null) {
        String password1 = aesUtils.decrypt(share.getPassword());
        if (!Objects.equals(password, password1)) {
            return Result.error("密码错误");
        }
    }
    // 检查过期时间是否为空
    if (share.getExpireTime() == null) {
        return Result.error("分享链接已过期");
    }

    // 解析存储的字符串格式时间
    LocalDateTime expireTime = LocalDateTime.parse(share.getExpireTime(), FORMATTER);
    if (expireTime.isBefore(LocalDateTime.now())) {
        return Result.error("分享链接已过期");
    }

    // 3. 返回文件元数据与分享信息。
    GetShare getShare = new GetShare();
    FileMetadata file = sharesMapper.getFile(share.getFileId());
    getShare.setId(file.getId());
    getShare.setFileName(file.getFileName());
    getShare.setFileSize(file.getFileSize());
    getShare.setIsDirectory(file.getIsDirectory());
    GetshareVo shareVo = new GetshareVo();
    shareVo.setFile(getShare);
    shareVo.setExpireTime(expireTime);
    return Result.success(shareVo);
}

    @Autowired
    private FilesService fileService;
    @Override
    public void downloadShare(String shareId, String password,HttpServletResponse response) throws Exception {
        //1. 先查 Redis，未命中再查 MySQL。
        String shareInfo = stringRedisTemplate.opsForValue().get(RedisConstants.share_prefix + shareId);
        if (shareInfo == null) {
            Share share = this.getById(shareId);
            if (share == null) {
                log.error("文件不存在，文件Id：{}", shareId);
                sendErrorResponse(response, "文件不存在");
                return;
            }
        }
        //2. 校验密码及过期时间。
        Share_Redis share = JSONUtil.toBean(shareInfo, Share_Redis.class);
        LocalDateTime expireTime = LocalDateTime.parse(share.getExpireTime(), FORMATTER);
        if (expireTime.isBefore(LocalDateTime.now())) {
            log.error("文件已过期，文件Id：{}", shareId);
            sendErrorResponse(response, "文件已过期");
            return;
        }
        String password1 = aesUtils.decrypt(share.getPassword());
        if (share.getPassword() != null ) {
            if (!Objects.equals(password, password1)) {
                log.error("密码错误，文件Id：{}", shareId);
                sendErrorResponse(response, "密码错误");
                return;
            }
        }
        try {
            fileService.downloadFile(share.getFileId(), share.getUserId(), response);
            Long userId = BaseContext.getCurrentId();
                log.info("用户请求下载分享文件 {}",share.getFileId());
            } catch (RuntimeException e) {
                log.error("文件下载业务异常 - 分享文件ID: {}", shareId, e);
                sendErrorResponse(response, e.getMessage());
            } catch (IOException e) {
                log.error("文件下载IO异常 - 分享文件ID: {}", shareId, e);
                sendErrorResponse(response, "文件下载失败");
            } catch (Exception e) {
                log.error("文件下载系统异常 - 分享文件ID: {}", shareId, e);
                sendErrorResponse(response, "系统错误");
            }
        }

        /**
         * 发送错误响应（JSON格式）
         */
        private void sendErrorResponse(HttpServletResponse response, String errorMessage) {
            try {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                response.setContentType("application/json;charset=UTF-8");

                Map<String, Object> errorResult = new HashMap<>();
                errorResult.put("code", 2);
                errorResult.put("msg", errorMessage);
                errorResult.put("data", null);

                String jsonResponse = new com.fasterxml.jackson.databind.ObjectMapper()
                        .writeValueAsString(errorResult);

                response.getWriter().write(jsonResponse);
                response.getWriter().flush();
            } catch (IOException ioException) {
                log.error("发送错误响应失败", ioException);
            }
        }

}
